package com.xsj.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.xsj.mapper.CartMapper;
import com.xsj.mapper.GoodsMapper;
import com.xsj.mapper.MerchantMapper;
import com.xsj.mapper.SpecificationMapper;
import com.xsj.pojo.Goods;
import com.xsj.pojo.Merchant;
import com.xsj.service.CartService;
import com.xsj.vo.*;
import org.apache.catalina.security.SecurityUtil;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.Security;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.ErrorManager;
import java.util.stream.Collectors;


/**
 * @BelongsProject: wisdom-restaurant-manage
 * @BelongsPackage: com.xsj.service.impl
 * @Author: tutu
 * @CreateTime: 2025-06-16 15:09
 * @Description: TODO
 * @Version: 1.0
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private CartMapper cartMapper;

    @Autowired
    private MerchantMapper merchantMapper;

    private final ObjectMapper objectMapper = new ObjectMapper();



    //把购物车信息添加到redis
    @Override
    public int addCart(Cart cart) {
        if (cart != null && cart.getMerchantId() != null) {
            int userId = cart.getUserId();
            String redisKey = "cart:" + userId + ":" + cart.getMerchantId();
            String goodId = cart.getGoodsId().toString();
            redisTemplate.opsForHash().put(redisKey, goodId, cart);
            redisTemplate.expire(redisKey, 1, TimeUnit.HOURS);
            return 1;
        }
        return 0;
    }


    @Override
    public Map<Integer, Cart> getCartFromRedis(int userId, int merchantId) {
        String redisKey = "cart:" + userId + ":" + merchantId;
        if (!redisTemplate.hasKey(redisKey)) {
            return Collections.emptyMap();
        }
        Map<Object, Object> rawData = redisTemplate.opsForHash().entries(redisKey);
        HashMap<Integer, Cart> result = new HashMap<>();
        for (Map.Entry<Object, Object> entry : rawData.entrySet()) {
            try {
                //将键转换为商品Id
                int goodInt = Integer.parseInt(entry.getKey().toString());

                //值是一个JSON字符串，需要二次解析
                String s = entry.getValue().toString();

                //解析为Cart对象
                Cart cart = objectMapper.readValue(s, Cart.class);

                result.put(goodInt, cart);
            } catch (Exception e) {
                return null;

            }
        }
        return result;

    }

    @Override
    public Map<String, Cart> getCartForMerchant(int userId, int merchantId) {
        List<Cart> cartList = cartMapper.findByUserIdAndMerchantId(userId, merchantId);
        if (cartList == null || cartList.isEmpty()) {
            return Collections.emptyMap();
        }

        HashMap<String, Cart> result = new HashMap<>();
        for (Cart item : cartList) {
            //将spec_json字符串反序列化会List<Spec>
            String specsJson = item.getSpecsJson();
            if (specsJson != null) {
                try {
                    List<Spec> specs = objectMapper.readValue(specsJson, new TypeReference<List<Spec>>() {
                    });
                    item.setSpecs(specs);
                } catch (Exception e) {
                    System.err.println("反序列化规格JSON失败, goodsId: " + item.getGoodId() + ", error: " + e.getMessage());
                    // 出错时可以给一个空列表，避免后续操作空指针
                    item.setSpecs(Collections.emptyList());
                }
            }
            //生成与前端一致的Map Key
            String cartKey;
            if (item.getSpecs() != null && !item.getSpecs().isEmpty()) {
                String specValues = item.getSpecs().stream().map(Spec::getVal_id).sorted().collect(Collectors.joining("_"));
                cartKey = item.getGoodId() + "_" + specValues;
            } else {
                cartKey = String.valueOf(item.getGoodId());
            }
            result.put(cartKey, item);
        }
        return result;

    }

    @Override
    public int addCartToMySQL(int userId, int merchantId) {
        Map<Integer, Cart> cartFromRedis = getCartFromRedis(userId, merchantId);
        Set<Integer> redisGoodIds = cartFromRedis.keySet();

        //从MYSQL获取该用户在该商家的旧购物车状态
        List<Cart> mysqlCartList = cartMapper.findByUserIdAndMerchantId(userId, merchantId);
        Set<Integer> mysqlGoodIds = mysqlCartList.stream().map(Cart::getGoodId).collect(Collectors.toSet());
        //找出需要删除的旧购物车项目
        HashSet<Integer> idsToDelete = new HashSet<>(mysqlGoodIds);
        idsToDelete.removeAll(redisGoodIds);

        int deletedCount = 0;
        if(!idsToDelete.isEmpty()){
            deletedCount = cartMapper.deleteByGoodIds(userId, merchantId, new ArrayList<>(idsToDelete));
            System.out.println("从 MySQL 同步删除了 " + deletedCount + " 个商品。");
        }

        // 将 Redis 中的购物车数据同步到 MySQL
        if (cartFromRedis.isEmpty()){
            return deletedCount;
        }

        int upsertCount = 0;
        for (Cart item: cartFromRedis.values()) {
            try {
                if (item.getSpecs() != null && !item.getSpecs().isEmpty()) {
                    String specsJson = objectMapper.writeValueAsString(item.getSpecs());
                    item.setSpecsJson(specsJson);
                }
                upsertCount += cartMapper.addCart(item);
            } catch (Exception e) {
                System.out.println("获取套餐信息失败"); // 打印消息
                e.printStackTrace(); // 打印异常堆栈（完整信息）
            }
        }
        System.out.println("从 Redis 同步到 MySQL 成功, 新增/更新了 " + upsertCount + " 个商品。");
        return deletedCount+upsertCount;

    }



    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private SpecificationMapper specificationMapper;

    @Override
    public List<MerchantCartVO> findByUserId(int userId) {
        // 1. 从数据库一次性获取所有购物车项目（已包含商品和商家基本信息）
        List<Cart> allCarts = cartMapper.findByUserId(userId);
        if (allCarts == null || allCarts.isEmpty()) {
            return Collections.emptyList();
        }

        // 2. 收集所有需要查询详情的规格值ID (val_id)
        Set<Integer> allValueIds = new HashSet<>();
        allCarts.forEach(cart -> {
            String specsJson = cart.getSpecsJson();
            if (StringUtils.hasText(specsJson)) {
                try {
                    List<Spec> specs = objectMapper.readValue(specsJson, new TypeReference<List<Spec>>() {
                    });
                    cart.setSpecs(specs); // 将解析后的对象存回cart，方便后续使用
                    specs.forEach(spec -> allValueIds.add(Integer.valueOf(spec.getVal_id())));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        // 3. 批量查询所有规格的详细信息
        Map<Integer, SpecDetailVO> specDetailsMap = new HashMap<>();
        if (!allValueIds.isEmpty()) {
            List<SpecDetailVO> specDetails = specificationMapper.findDetailsByValueIds(allValueIds);
            // 将结果转为Map，以val_id为键，方便快速查找
            specDetailsMap = specDetails.stream()
                    .collect(Collectors.toMap(SpecDetailVO::getValId, specDetail -> specDetail));
        }

        // 4. 按商家ID对购物车项目进行分组
        Map<Integer, List<Cart>> groupedByMerchant = allCarts.stream()
                .collect(Collectors.groupingBy(Cart::getMerchantId));

        // 5. 将分组后的数据转换为前端需要的 List<MerchantCartVO> 结构
        final Map<Integer, SpecDetailVO> finalSpecDetailsMap = specDetailsMap; // for use in lambda
        return groupedByMerchant.entrySet().stream()
                .map(entry -> {
                    Integer merchantId = entry.getKey();
                    List<Cart> carts = entry.getValue();
                    Cart firstCart = carts.get(0); // 同一个商家的信息是一样的，取第一个即可

                    // 6. 转换每个商家内部的商品列表
                    List<CartItemVO> cartItems = carts.stream().map(cart -> {
                        CartItemVO itemVO = new CartItemVO();
                        itemVO.setGoodId(cart.getGoodId());
                        itemVO.setGoodName(cart.getGoodName());
                        itemVO.setGoodIcon(cart.getGoodIcon());
                        itemVO.setPrice(cart.getPrice());
                        itemVO.setQuantity(cart.getGoodNum());
                        itemVO.setSpecs(cart.getSpecs());

                        // 7. 构建可读的规格文本 (specsText)
                        if (cart.getSpecs() != null && !cart.getSpecs().isEmpty()) {
                            String specsText = cart.getSpecs().stream()
                                    .map(spec -> finalSpecDetailsMap.get(Integer.valueOf(spec.getVal_id())))
                                    .filter(Objects::nonNull)
                                    .map(detail -> detail.getSpeType() + ": " + detail.getSpeVal())
                                    .collect(Collectors.joining(", "));
                            itemVO.setSpecsText(specsText);
                        }
                        return itemVO;
                    }).collect(Collectors.toList());

                    // 8. 组装最终的 MerchantCartVO
                    MerchantCartVO merchantCartVO = new MerchantCartVO();
                    merchantCartVO.setMerchantId(merchantId);
                    merchantCartVO.setMerchantName(firstCart.getMerchantName());

                    merchantCartVO.setCartItems(cartItems);
                    return merchantCartVO;
                })
                .collect(Collectors.toList());
    }

    @Override
    public int deleteCartFromRedis(int userId, int merchantId,int goodId) {
// 1. 构造与 addCart 方法中完全一致的 Redis Key
        String redisKey = "cart:" + userId + ":" + merchantId;
        // 2. 将要删除的 goodId 转换为字符串，作为 Hash 的 field
        String hashField = String.valueOf(goodId);
        // 3. 调用 opsForHash().delete() 方法，传入 key 和要删除的 field
        //    该方法会返回被成功删除的 field 数量 (返回值为 Long)
        Long delete = redisTemplate.opsForHash().delete(redisKey, hashField);

        // 4. 返回删除的条目数。如果什么都没删除，deletedCount 会是 0。
        //    进行一个 null 检查以确保安全。
        return delete != null ? delete.intValue() : 0;
    }

    @Override
    public int deleteToMySQL(int userId, int merchantId, int goodId) {
        return cartMapper.deleteGoodByMySQL(userId, merchantId, goodId);
    }

}